//
//  NSPropertyListXmlrpcSerialization.m
//  xmlrpc
//
//  Created by Daniel Braun on 18/09/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "NSPropertyListXmlrpcSerialization.h"
static id objWithXml(NSXMLElement *el);

@interface NSString (xmlrpcSerialisation)
- (NSXMLElement *) xmlrpcRepresentation;
+ (id) objectWithXmlrpc:(NSString*)name value:(NSXMLElement *)elv;
@end
@implementation NSString (xmlrpcSerialisation)
- (NSXMLElement *) xmlrpcRepresentation
{
	return [NSXMLElement elementWithName:@"string" stringValue:self];
}
+ (id) objectWithXmlrpc:(NSString*)name value:(NSXMLElement *)elv
{
	NSString *v=[elv stringValue];
	if (![name isEqualToString:@"string"]) return nil;
	return [NSString stringWithString:v];
}
@end



@interface NSNumber (xmlrpcSerialisation)
- (NSXMLElement *) xmlrpcRepresentation;
+ (id) objectWithXmlrpc:(NSString*)name value:(NSXMLElement *)elv;
@end
@implementation NSNumber (xmlrpcSerialisation)
+ (id) objectWithXmlrpc:(NSString*)name value:(NSXMLElement *)elv
{
	NSString *v=[elv stringValue];
	if ([name isEqualToString:@"true"]) return [NSNumber numberWithBool:YES];
	else if ([name isEqualToString:@"false"]) return [NSNumber numberWithBool:NO];
	else if ([name isEqualToString:@"real"]) return [NSNumber numberWithDouble:[v doubleValue]];
	else if ([name isEqualToString:@"integer"]) return [NSNumber numberWithInt:[v intValue]];
	return nil;
}
- (NSXMLElement *) xmlrpcRepresentation
{
	CFNumberType cn=CFNumberGetType((CFNumberRef)self);
	switch (cn) {
		case   kCFNumberCharType :
			return [NSXMLElement elementWithName:[self boolValue]?@"true":@"false"];

		case  kCFNumberSInt8Type :
		case   kCFNumberSInt16Type :
		case   kCFNumberSInt32Type :
		case   kCFNumberSInt64Type :
		case   kCFNumberShortType:
		case   kCFNumberIntType :
		case   kCFNumberLongType :
		case   kCFNumberLongLongType :
		case   kCFNumberCFIndexType :
			return [NSXMLElement elementWithName:@"integer" stringValue:[self description]];

		case   kCFNumberFloat32Type :
		case   kCFNumberFloat64Type :
		case   kCFNumberFloatType :
		case   kCFNumberDoubleType :
			return [NSXMLElement elementWithName:@"real" stringValue:[self description]];
		
	}	
			
	return [NSXMLElement elementWithName:@"number" stringValue:[self description]];
}
@end


@interface NSArray (xmlrpcSerialisation)
- (NSXMLElement *) xmlrpcRepresentation;
+ (id) objectWithXmlrpc:(NSString*)name value:(NSXMLElement *)elv;
@end
@implementation NSArray (xmlrpcSerialisation)

+ (id) objectWithXmlrpc:(NSString*)name value:(NSXMLElement *)elv
{
	if (![name isEqualToString:@"array"]) return nil;
	NSArray *ne=[elv children];
	NSMutableArray *v=[NSMutableArray arrayWithCapacity:[ne count]];
	unsigned int i, count = [ne count];
	for (i = 0; i < count; i++) {
		NSXMLElement * e = [ne objectAtIndex:i];
		id vo=objWithXml(e);
		if (!vo) continue;
		[v addObject:vo];
	}
	return v;
}

- (NSXMLElement *) xmlrpcRepresentation
{
	NSMutableArray *re=[NSMutableArray arrayWithCapacity:[self count]];
	unsigned int i, count = [self count];
	for (i = 0; i < count; i++) {
		NSObject * obj = [self objectAtIndex:i];
		[re addObject:[(id)obj xmlrpcRepresentation]];
	}
	return [NSXMLElement elementWithName:@"array" 
					 children:re
				      attributes:nil];
}
@end


@interface NSDictionary (xmlrpcSerialisation)
- (NSXMLElement *) xmlrpcRepresentation;
+ (id) objectWithXmlrpc:(NSString*)name value:(NSXMLElement *)elv;
@end
@implementation NSDictionary (xmlrpcSerialisation)

+ (id) objectWithXmlrpc:(NSString*)name value:(NSXMLElement *)elv
{
	if (![name isEqualToString:@"dict"]) return nil;
	NSArray *ne=[elv children];
	NSMutableDictionary *v=[NSMutableDictionary dictionaryWithCapacity:[ne count]/2];
	
	unsigned int i, count = [ne count];
	for (i = 0; i < count; i++) {
		NSXMLElement * xk = [ne objectAtIndex:i];
		if (![[xk name] isEqualToString:@"key"]) {
			continue;
		}
		NSString *key=[xk stringValue];
		i++;
		NSXMLElement * xv = [ne objectAtIndex:i];
		id vo=objWithXml(xv);
		if (!vo) continue;
		[v setObject:vo forKey:key];
	}
	return v;
}

- (NSXMLElement *) xmlrpcRepresentation
{
	NSMutableArray *re=[NSMutableArray arrayWithCapacity:[self count]];
	NSEnumerator *en=[self keyEnumerator];
	NSString *key;
	while ((key=[en nextObject])) {
		if (![key isKindOfClass:[NSString class]]) continue;
		NSXMLElement *xk=[NSXMLElement elementWithName:@"key" stringValue:key];
		id v=[self objectForKey:key];
		NSXMLElement *xv=[v xmlrpcRepresentation];
		[re addObject:xk];
		[re addObject:xv];
	}
	return [NSXMLElement elementWithName:@"dict" 
				 children:re
			       attributes:nil];
	

}
@end



@implementation NSPropertyListXmlrpcSerialization


+ (BOOL)propertyList:(id)plist isValidForFormat:(NSPropertyListFormat)format
{
	return [[NSPropertyListSerialization class] propertyList:plist isValidForFormat:format];
}
+ (NSData *)dataFromPropertyList:(id)plist format:(NSPropertyListFormat)format errorDescription:(NSString **)errorString
{
	if (format!=DB_PropertyListXMLRPCFormat) {
		NSData *d=[[NSPropertyListSerialization class] dataFromPropertyList:plist format:format 
				  errorDescription:errorString];
		if (0) NSLog(@"for %@ got %@\n", plist, [[[NSString alloc]initWithData:d
							       encoding:NSISOLatin1StringEncoding]autorelease]);
		return d;
	} else {
		//NSError *err=nil;
		NSXMLElement *re=[plist xmlrpcRepresentation];
		NSXMLDocument *d=[NSXMLDocument documentWithRootElement:re];
		[d setDocumentContentKind:NSXMLDocumentXMLKind];
		[d setCharacterEncoding:@"UTF-8"];
		[d setVersion:@"1.0"];
		//NSXMLDTD *dtd=[[NSXMLDTD alloc]initWithKind:NSXMLEntityGeneralKind];
		//[dtd setSystemID:@"-//Apple Computer//DTD PLIST 1.0//EN"];
		//if (1) [d setDTD:dtd];
		//[dtd release];
		return [d XMLDataWithOptions:0 /*|NSXMLDocumentTidyXML | NSXMLDocumentValidate*/];
	}
	return nil;
}

static id objWithXml(NSXMLElement *el)
{
	NSString *name=[el name];
	//NSString *v=[el stringValue];
	id obj=nil;
	obj=[NSNumber objectWithXmlrpc:name value:el];
	if (obj) return obj;
	obj=[NSString objectWithXmlrpc:name value:el];
	if (obj) return obj;
	//obj=[NSData objectWithXmlrpc:name value:el];
	//if (obj) return obj;
	obj=[NSDictionary objectWithXmlrpc:name value:el];
	if (obj) return obj;
	obj=[NSArray objectWithXmlrpc:name value:el];
	if (obj) return obj;
	return nil;
}

+ (id)propertyListFromData:(NSData *)data mutabilityOption:(NSPropertyListMutabilityOptions)opt format:(NSPropertyListFormat *)format errorDescription:(NSString **)errorString;
{
	NSError *err=nil;
	NSXMLDocument *xml=[[NSXMLDocument alloc] initWithData:data 
						       options:0 error:&err];
	//NSLog(@"got dtd %@\n", [xml DTD]);
	if (![[[xml rootElement]name] isEqualToString:@"plist"]) {
		return objWithXml([xml rootElement]);
			
	}
	return [[NSPropertyListSerialization class]propertyListFromData:data mutabilityOption:opt format:format errorDescription:errorString];
}


@end
